package com.brillilab.service.logic.space;

import com.brillilab.common.constant.ResultEnum;
import com.brillilab.common.exceptions.BrillilabException;
import com.brillilab.domain.enums.lab.LabMemberPowerEnum;
import com.brillilab.domain.enums.space.BoxTypeEnum;
import com.brillilab.domain.enums.space.PanelSizeEnum;
import com.brillilab.domain.enums.space.SpaceTypeEnum;
import com.brillilab.domain.po.hardware.HardWareOperateRecord;
import com.brillilab.domain.po.lab.Lab;
import com.brillilab.domain.po.space.*;
import com.brillilab.domain.vo.common.KeyValue;
import com.brillilab.domain.vo.inventory.PanelInventoryCount;
import com.brillilab.domain.vo.kit.ReagentTypeVo;
import com.brillilab.domain.vo.lab.LabMemberVo;
import com.brillilab.domain.vo.print.DevicePrintVo;
import com.brillilab.domain.vo.print.PanelPrintVo;
import com.brillilab.domain.vo.space.*;
import com.brillilab.domain.vo.user.UserInfoVo;
import com.brillilab.service.core.hardware.IHardwareOperateRecordService;
import com.brillilab.service.core.inventory.IReagentInventoryService;
import com.brillilab.service.core.kit.IReagentTypeService;
import com.brillilab.service.core.lab.ILabMemberService;
import com.brillilab.service.core.lab.ILabService;
import com.brillilab.service.core.space.IBoxService;
import com.brillilab.service.core.space.IDeviceService;
import com.brillilab.service.core.space.IKitBoxService;
import com.brillilab.service.core.space.IPanelService;
import com.brillilab.service.core.system.IDictService;
import com.google.common.base.Splitter;
import com.mchange.lang.LongUtils;
import org.apache.commons.collections.ListUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author wuzhiyu
 * @Title: PanelLogic
 * @ProjectName brill_lab
 * @Description: TODO
 * @date 2018/11/1514:14
 */
@Service
@Transactional
public class PanelLogic {
    @Resource
    private IReagentInventoryService reagentInventoryService;
    @Resource
    private IBoxService boxService;
    @Resource
    private IPanelService panelService;
    @Resource
    private IDeviceService deviceService;
    @Resource
    private IReagentTypeService reagentTypeService;
    @Resource
    private ILabMemberService labMemberService;
    @Resource
    private IDictService dictService;
    @Resource
    private IKitBoxService kitBoxService;
    @Resource
    private ILabService labService;
    @Resource
    private IHardwareOperateRecordService hardwareOperateRecordService;

    public boolean deleteList(List<Long> idList) {
        idList.forEach(o -> {
            if (reagentInventoryService.InventoryCountInSpace(o, SpaceTypeEnum.PANEL) > 0) {
                throw new BrillilabException(ResultEnum.DATA_EXIST_CANT_DELETE);
            }
        });
        panelService.deleteList(idList);
        boxService.deleteByPanelIdList(idList);
        kitBoxService.deleteByPanelIdList(idList);
        panelService.deletePanelGridUsedByPanelIdList(idList);
        return true;
    }

    public boolean merge(PanelMerge panelMerge, UserInfoVo userInfo) {
        Long panelId = null;
        if (!CollectionUtils.isEmpty(panelMerge.getUpdateList())) {
            panelId = panelMerge.getUpdateList().get(0).getId();
        } else {
            panelId = panelMerge.getDelList().get(0);
        }
        Panel panel = panelService.get(panelId);
        Assert.notNull(panel, "平面不存在");
        List<Panel> panelList = panelService.getPanelList(panel.getDeviceId());
        List<Long> pidList = panelList.stream().map(Panel::getId).collect(Collectors.toList());
        List<PanelInventoryCount> cntList = deviceService.getPanelInventoryCount(panel.getDeviceId());
        List<Long> hasInvPanelIdList = cntList.stream().map(PanelInventoryCount::getPanelId).collect(Collectors.toList());
        if (!CollectionUtils.isEmpty(panelMerge.getDelList())) {
            Assert.isTrue(pidList.containsAll(panelMerge.getDelList()), "平面不能操作");
        }
        if (!CollectionUtils.isEmpty(panelMerge.getUpdateList())) {
            List<Long> updateIdList = panelMerge.getUpdateList().stream().map(PanelUpdate::getId).collect(Collectors.toList());
            Assert.isTrue(pidList.containsAll(updateIdList), "平面不能操作");
            Assert.isTrue(!hasInvPanelIdList.stream().anyMatch(id -> updateIdList.contains(id)), "平面有库存");
        }
        if (!CollectionUtils.isEmpty(panelMerge.getDelList())) {
            Assert.isTrue(!hasInvPanelIdList.stream().anyMatch(id -> panelMerge.getDelList().contains(id)), "平面有库存");
        }
        if (!CollectionUtils.isEmpty(panelMerge.getUpdateList())) {
            List<Panel> updatePanelList = panelMerge.getUpdateList().stream().map(update -> {
                Panel toUpdate = new Panel();
                toUpdate.setId(update.getId());
                toUpdate.setX(update.getX());
                toUpdate.setY(update.getY());
                toUpdate.setHeight(update.getHeight());
                toUpdate.setWidth(update.getWidth());
                toUpdate.setIsDelete(0);
                toUpdate.setUserReagentType(update.getReagentTypes());
                toUpdate.setLabMemberId(update.getLabMemberId());
                toUpdate.setColumns(update.getColumns());
                toUpdate.setRows(update.getRows());
                return toUpdate;
            }).collect(Collectors.toList());
            panelService.updateList(updatePanelList);
        }
        if (!CollectionUtils.isEmpty(panelMerge.getAddList())) {
            List<Panel> addList = panelMerge.getAddList().stream().map(add -> {
                Panel newPanel = new Panel();
                BeanUtils.copyProperties(panel, newPanel);
                BeanUtils.copyProperties(add, newPanel);
                newPanel.setId(null);
                newPanel.setCreateTime(null);
                newPanel.setUpdateTime(null);
                newPanel.setIsDelete(0);
                newPanel.setRemark(add.getRemark());
                newPanel.setLabMemberId(add.getLabMemberId());
                newPanel.setColumns(add.getColumns());
                newPanel.setRows(add.getRows());
                newPanel.setSetReagentType(null);
                newPanel.setSysReagentType(null);
                newPanel.setUserReagentType(add.getReagentTypes());
                return newPanel;
            }).collect(Collectors.toList());
            panelService.addList(addList);
        }
        if (!CollectionUtils.isEmpty(panelMerge.getDelList())) {
            panelService.deleteList(panelMerge.getDelList());
            boxService.deleteByPanelIdList(panelMerge.getDelList());
            kitBoxService.deleteByPanelIdList(panelMerge.getDelList());
            panelService.deletePanelGridUsedByPanelIdList(panelMerge.getDelList());
        }
        return true;
    }

    public DeviceWithPanelInfoVo getPanelList(Long deviceId, UserInfoVo user) {
        Device device = deviceService.get(deviceId);
        Assert.isTrue(device.getLabId().equals(user.getLabId()), "device not exist");
        Map<Integer, String> zoneMap = dictService.getZoneMap();
        List<Panel> list = panelService.getPanelList(deviceId);
        List<LabMemberVo> memList = labMemberService.selectList(device.getLabId(), null);
        List<ReagentTypeVo> typeList = reagentTypeService.selectAllSuReagentType(user.getLabId(), null, null,null);
        DeviceWithPanelInfoVo vo = new DeviceWithPanelInfoVo();
        DeviceVo dvo = new DeviceVo();
        BeanUtils.copyProperties(device, dvo);
        dvo.setZoneName(zoneMap.get(device.getZone()));
        vo.setDevice(dvo);
        List<PanelInfoVo> plist = new ArrayList<>();
        vo.setPanelList(plist);
        list.forEach(p -> {
            PanelInfoVo pvo = new PanelInfoVo();
            pvo.setPanelId(p.getId());
            pvo.setName(p.getName());
            pvo.setHeight(p.getHeight());
            pvo.setWidth(p.getWidth());
            pvo.setX(p.getX());
            pvo.setY(p.getY());
            pvo.setColumns(p.getColumns());
            pvo.setRows(p.getRows());
            pvo.setSizeStr(PanelSizeEnum.getMap().get(p.getColumns())+ "*" + PanelSizeEnum.getMap().get(p.getRows()) );
            pvo.setLabMemberName(p.getLabMemberId() == null ? "公用" : memList.stream().filter(m -> m.getLabMemberId().equals(p.getLabMemberId())).findFirst().get().getUserName());
            pvo.setLabMemberId(p.getLabMemberId());
            pvo.setRemark(p.getRemark());
            pvo.setUserReagentType(p.getUserReagentType());
            if (!StringUtils.isEmpty(p.getUserReagentType())) {
                List<String> arr = Splitter.on(",").omitEmptyStrings().splitToList(p.getUserReagentType());
                if (arr != null && arr.size() > 0) {
                    List<ReagentTypeVo> typeVoList = reagentTypeService.getTypeList(p.getLabId(), null);
                    StringBuffer sb = new StringBuffer();
                    for (int x = 0; x < arr.size(); x++) {
                        Long i = new Long(arr.get(x));
                        Optional<ReagentTypeVo> opt = typeVoList.stream().filter(o -> o.getReagentTypeId().equals(i)).findFirst();
                        if (opt.isPresent()) {
                            if (x == arr.size() - 1) {
                                sb.append(opt.get().getName());
                            } else {
                                sb.append(opt.get().getName() + ",");
                            }
                        }
                    }
                    pvo.setTags(sb.toString());
                }
            }
            pvo.setCanSee(p.getLabMemberId() == null ? true : (user.hasPower(LabMemberPowerEnum.Power.REAGENT) || user.getLabMemberId().equals(p.getLabMemberId())));
            plist.add(pvo);
        });

        //锁和摄像头信息
        HardWareOperateRecord hardWare = hardwareOperateRecordService.selectByDeviceId(deviceId);
        if (hardWare != null) {
            DeviceVo deviceVo = vo.getDevice();
            deviceVo.setLockerId(hardWare.getLockerId());
            deviceVo.setCamIp(hardWare.getCamIp());
            vo.setDevice(deviceVo);
        }
        plist.sort((x,y)->x.getName().compareTo(y.getName()));
        return vo;
    }

    public boolean updateBoxPosition(Box box, KitBox kitBox, List<PanelGridUsed> panelGridUsedList) {
        Integer x = Integer.valueOf(100);
        Integer y = Integer.valueOf(100);
        panelService.deletePanelGridUsed(panelGridUsedList);
        List<PanelGridUsed> dbUsedList = panelService.getPanelGridUsedList(panelGridUsedList.get(0).getPanelId());
        if (box != null && panelGridUsedList.get(0).getBoxId() != null) {
            for (PanelGridUsed used : panelGridUsedList) {
                Optional<PanelGridUsed> opt = dbUsedList.stream().filter(u -> u.getRowNo().equals(used.getRowNo()) && u.getColumnNo().equals(used.getColumnNo())).findAny();
                if (opt.isPresent()) {
                    throw new BrillilabException(ResultEnum.DATA_IN_USING);
                }
                if (used.getColumnNo() <= x) {
                    x = used.getColumnNo();
                }
                if (used.getRowNo() <= y) {
                    y = used.getRowNo();
                }
            }
            Box newBox = new Box();
            newBox.setId(box.getId());
            newBox.setX(x);
            newBox.setY(y);
            boxService.updateById(newBox);
        } else if (kitBox != null && panelGridUsedList.get(0).getKitBoxId() != null) {
            for (PanelGridUsed used : panelGridUsedList) {
                Optional<PanelGridUsed> opt = dbUsedList.stream().filter(u -> u.getRowNo().equals(used.getRowNo()) && u.getColumnNo().equals(used.getColumnNo())).findAny();
                if (opt.isPresent()) {
                    throw new BrillilabException(ResultEnum.DATA_IN_USING);
                }
                if (used.getColumnNo() <= x) {
                    x = used.getColumnNo();
                }
                if (used.getRowNo() <= y) {
                    y = used.getRowNo();
                }
            }
            KitBox newBox = new KitBox();
            newBox.setId(kitBox.getId());
            newBox.setX(x);
            newBox.setY(y);
            kitBoxService.update(newBox);
        }
        panelService.addPanelGridUsedList(panelGridUsedList);
        return true;
    }

    public List<KeyValue<String, List<KeyValue<String, List<PanelPrintVo>>>>> getPrintList(Long labId) {
        List<Panel> panelList = panelService.getLabPanelList(labId);
        List<KeyValue<String, List<KeyValue<String, List<PanelPrintVo>>>>> list = new ArrayList<>();
        List<Room> roomList = panelList.stream().map(d -> {
            Room room = new Room();
            room.setId(d.getRoomId());
            room.setName(d.getRoomName());
            return room;
        }).distinct().collect(Collectors.toList());
        Map<Integer, String> zoneMap = dictService.getZoneMap();
        Lab lab = labService.selectById(labId);
        roomList.forEach(r -> {
            KeyValue<String, List<KeyValue<String, List<PanelPrintVo>>>> kvr = new KeyValue<>();
            list.add(kvr);
            kvr.setKey(r.getName());
            List<KeyValue<String, List<PanelPrintVo>>> kvd = new ArrayList<>();
            kvr.setValue(kvd);
            List<Device> deviceList = panelList.stream().filter(p -> p.getRoomId().equals(r.getId())).map(p -> {
                Device d = new Device();
                d.setId(p.getDeviceId());
                d.setDeviceIndex(p.getDeviceIndex());
                d.setZone(p.getZone());
                return d;
            }).distinct().collect(Collectors.toList());
            deviceList.forEach(d -> {
                KeyValue<String, List<PanelPrintVo>> kvp = new KeyValue<>();
                kvd.add(kvp);
                kvp.setKey(d.getDeviceIndex() + "[" + zoneMap.get(d.getZone()) + "]");
                List<PanelPrintVo> printVoList = panelList.stream().filter(p -> p.getDeviceId().equals(d.getId())).map(p -> {
                    PanelPrintVo vo = new PanelPrintVo();
                    vo.setDeviceName(d.getDeviceIndex() + "");
                    vo.setDeviceIndex(d.getDeviceIndex());
                    vo.setPanelName(p.getName());
                    vo.setPanelId(p.getId());
                    vo.setRoomName(r.getName());
                    vo.setZoneName(zoneMap.get(p.getZone()));
                    vo.setQrCode("labinone://inventoryQuery?panelId=" + p.getId());
                    vo.setRemark(p.getRemark());
                    return vo;
                }).collect(Collectors.toList());
                kvp.setValue(printVoList);
            });
        });
        return list;
    }

    public PanelVo getPanel(Panel panel) {
        PanelVo panelVo = new PanelVo();
        BeanUtils.copyProperties(panel, panelVo);
        Map<Integer, String> zoneMap = dictService.getZoneMap();
        panelVo.setZoneName(zoneMap.get(panel.getZone()));
        if (panel.getLabMemberId() != null) {
            LabMemberVo labMemberVo = labMemberService.selectMemberVo(panel.getLabMemberId());
            panelVo.setOwnerName(labMemberVo.getUserName());
        } else {
            panelVo.setOwnerName("公用");
        }
        if (!StringUtils.isEmpty(panel.getUserReagentType())) {
            List<String> arr = Splitter.on(",").omitEmptyStrings().splitToList(panel.getUserReagentType());
            if (arr != null && arr.size() > 0) {
                List<ReagentTypeVo> typeVoList = reagentTypeService.getTypeList(panel.getLabId(), null);
                StringBuffer sb = new StringBuffer();
                for (int x = 0; x < arr.size(); x++) {
                    Long i = new Long(arr.get(x));
                    Optional<ReagentTypeVo> opt = typeVoList.stream().filter(o -> o.getReagentTypeId().equals(i)).findFirst();
                    if (opt.isPresent()) {
                        if (x == arr.size() - 1) {
                            sb.append(opt.get().getName());
                        } else {
                            sb.append(opt.get().getName() + ",");
                        }
                    }
                }
                panelVo.setTags(sb.toString());
            }
        }
        return panelVo;
    }

    public PanelPrintVo getPrint(UserInfoVo user, Long panelId) {
        Panel panel = panelService.get(panelId);
        Assert.notNull(panel, "数据不存在");
        Assert.isTrue(panel.getLabId().equals(user.getLabId()), "数据不存在");
        Map<Integer, String> zoneMap = dictService.getZoneMap();
        PanelPrintVo vo = new PanelPrintVo();
        vo.setDeviceName(panel.getDeviceIndex() + "");
        vo.setDeviceIndex(panel.getDeviceIndex());
        vo.setPanelName(panel.getName());
        vo.setPanelId(panel.getId());
        vo.setRoomName(panel.getRoomName());
        vo.setZoneName(zoneMap.get(panel.getZone()));
        vo.setQrCode("labinone://inventoryQuery?panelId=" + panel.getId());
        vo.setRemark(panel.getRemark());
        return vo;
    }

    public Map<Long, BoxPositionData> getKitBoxPositionData(List<Long> kitBoxIdList) {
        List<PanelGridUsed> allList = panelService.getPanelGridUsedListByBoxIdList(kitBoxIdList, BoxTypeEnum.KIT_BOX);
        List<Long> panelIdList = allList.stream().map(PanelGridUsed::getPanelId).distinct().collect(Collectors.toList());
        List<Panel> panelList = panelService.getListByIdList(panelIdList);
        Map<Long, BoxPositionData> result = new HashMap<>();
        kitBoxIdList.forEach(k -> {
            List<PanelGridUsed> list = allList.stream().filter(o -> o.getKitBoxId().equals(k)).collect(Collectors.toList());
            BoxPositionData data = new BoxPositionData();
            if(list!=null && list.size()>0){
                data.setPanelGridUsedList(list);
                Panel panel = panelList.stream().filter(p -> p.getId().equals(list.get(0).getPanelId())).findFirst().get();
                data.setColumns(panel.getColumns());
                data.setRows(panel.getRows());
                result.put(k, data);
            }
        });
        return result;
    }

    public boolean update(Panel panel, boolean isChangeAll) {
        panelService.updateInfo(panel.getId(),panel.getRemark(),panel.getUserReagentType(),panel.getLabMemberId());
        if (panel.getLabMemberId()!=null) {
            panelService.updateInventoryOwnerByPanelId(panel.getId(), panel.getLabMemberId());
            boxService.updateBoxAndGridOwnerByPanelId(panel.getId(), panel.getLabMemberId());
        }else{
            if(isChangeAll){
                panelService.updateInventoryOwnerByPanelId(panel.getId(), panel.getLabMemberId());
                boxService.updateBoxAndGridOwnerByPanelId(panel.getId(), panel.getLabMemberId());
            }
        }
        return true;
    }
}
